{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Sebastian Raschka, 2015-2018  \n",
    "`mlxtend`, a library of extension and helper modules for Python's data analysis and machine learning libraries\n",
    "\n",
    "- GitHub repository: https://github.com/rasbt/mlxtend\n",
    "- Documentation: http://rasbt.github.io/mlxtend/"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Sebastian Raschka \n",
      "last updated: 2018-05-06 \n",
      "\n",
      "CPython 3.6.4\n",
      "IPython 6.2.1\n",
      "\n",
      "matplotlib 2.1.2\n",
      "numpy 1.12.1\n",
      "scipy 1.0.0\n",
      "mlxtend 0.13.0dev0\n"
     ]
    }
   ],
   "source": [
    "%load_ext watermark\n",
    "%watermark -a 'Sebastian Raschka' -u -d -v -p matplotlib,numpy,scipy,mlxtend"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Exhaustive Feature Selector"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Implementation of an *exhaustive feature selector* for sampling and evaluating all possible feature combinations in a specified range."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> from mlxtend.feature_selection import ExhaustiveFeatureSelector"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Overview"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This exhaustive feature selection algorithm is a wrapper approach for brute-force evaluation of feature subsets; the best subset is selected by optimizing a specified performance metric given an arbitrary regressor or classifier. For instance, if the classifier is a logistic regression and the dataset consists of 4 features, the alogorithm will evaluate all 15 feature combinations (if `min_features=1` and `max_features=4`)\n",
    "\n",
    "- {0}\n",
    "- {1}\n",
    "- {2}\n",
    "- {3}\n",
    "- {0, 1}\n",
    "- {0, 2}\n",
    "- {0, 3}\n",
    "- {1, 2}\n",
    "- {1, 3}\n",
    "- {2, 3}\n",
    "- {0, 1, 2}\n",
    "- {0, 1, 3}\n",
    "- {0, 2, 3}\n",
    "- {1, 2, 3}\n",
    "- {0, 1, 2, 3}\n",
    "\n",
    "and select the one that results in the best performance (e.g., classification accuracy) of the logistic regression classifier.\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example 1 - A simple Iris Example"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Initializing a simple classifier from scikit-learn:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Features: 15/15"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Best accuracy score: 0.97\n",
      "Best subset (indices): (0, 2, 3)\n",
      "Best subset (corresponding names): ('0', '2', '3')\n"
     ]
    }
   ],
   "source": [
    "from sklearn.neighbors import KNeighborsClassifier\n",
    "from sklearn.datasets import load_iris\n",
    "from mlxtend.feature_selection import ExhaustiveFeatureSelector as EFS\n",
    "\n",
    "iris = load_iris()\n",
    "X = iris.data\n",
    "y = iris.target\n",
    "\n",
    "knn = KNeighborsClassifier(n_neighbors=3)\n",
    "\n",
    "efs1 = EFS(knn, \n",
    "           min_features=1,\n",
    "           max_features=4,\n",
    "           scoring='accuracy',\n",
    "           print_progress=True,\n",
    "           cv=5)\n",
    "\n",
    "efs1 = efs1.fit(X, y)\n",
    "\n",
    "print('Best accuracy score: %.2f' % efs1.best_score_)\n",
    "print('Best subset (indices):', efs1.best_idx_)\n",
    "print('Best subset (corresponding names):', efs1.best_feature_names_)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that in the example above, the  'best_feature_names_' are simply a string equivalent of the feature indices. However, we can provide custom feature names to the `fit` function for this mapping:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Features: 15/15"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Best subset (corresponding names): ('sepal length', 'petal length', 'petal width')\n"
     ]
    }
   ],
   "source": [
    "feature_names = ('sepal length', 'sepal width', 'petal length', 'petal width')\n",
    "efs1 = efs1.fit(X, y, custom_feature_names=feature_names)\n",
    "print('Best subset (corresponding names):', efs1.best_feature_names_)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Via the `subsets_` attribute, we can take a look at the selected feature indices at each step:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{0: {'avg_score': 0.65999999999999992,\n",
       "  'cv_scores': array([ 0.53333333,  0.63333333,  0.73333333,  0.76666667,  0.63333333]),\n",
       "  'feature_idx': (0,),\n",
       "  'feature_names': ('sepal length',)},\n",
       " 1: {'avg_score': 0.56666666666666665,\n",
       "  'cv_scores': array([ 0.53333333,  0.63333333,  0.6       ,  0.5       ,  0.56666667]),\n",
       "  'feature_idx': (1,),\n",
       "  'feature_names': ('sepal width',)},\n",
       " 2: {'avg_score': 0.95333333333333337,\n",
       "  'cv_scores': array([ 0.93333333,  1.        ,  0.9       ,  0.93333333,  1.        ]),\n",
       "  'feature_idx': (2,),\n",
       "  'feature_names': ('petal length',)},\n",
       " 3: {'avg_score': 0.94666666666666666,\n",
       "  'cv_scores': array([ 0.96666667,  0.96666667,  0.93333333,  0.86666667,  1.        ]),\n",
       "  'feature_idx': (3,),\n",
       "  'feature_names': ('petal width',)},\n",
       " 4: {'avg_score': 0.72666666666666668,\n",
       "  'cv_scores': array([ 0.66666667,  0.8       ,  0.63333333,  0.86666667,  0.66666667]),\n",
       "  'feature_idx': (0, 1),\n",
       "  'feature_names': ('sepal length', 'sepal width')},\n",
       " 5: {'avg_score': 0.94666666666666666,\n",
       "  'cv_scores': array([ 0.96666667,  1.        ,  0.86666667,  0.93333333,  0.96666667]),\n",
       "  'feature_idx': (0, 2),\n",
       "  'feature_names': ('sepal length', 'petal length')},\n",
       " 6: {'avg_score': 0.95333333333333337,\n",
       "  'cv_scores': array([ 0.96666667,  0.96666667,  0.9       ,  0.93333333,  1.        ]),\n",
       "  'feature_idx': (0, 3),\n",
       "  'feature_names': ('sepal length', 'petal width')},\n",
       " 7: {'avg_score': 0.94666666666666666,\n",
       "  'cv_scores': array([ 0.96666667,  1.        ,  0.9       ,  0.93333333,  0.93333333]),\n",
       "  'feature_idx': (1, 2),\n",
       "  'feature_names': ('sepal width', 'petal length')},\n",
       " 8: {'avg_score': 0.94000000000000006,\n",
       "  'cv_scores': array([ 0.96666667,  0.96666667,  0.86666667,  0.93333333,  0.96666667]),\n",
       "  'feature_idx': (1, 3),\n",
       "  'feature_names': ('sepal width', 'petal width')},\n",
       " 9: {'avg_score': 0.95333333333333337,\n",
       "  'cv_scores': array([ 0.96666667,  0.96666667,  0.9       ,  0.93333333,  1.        ]),\n",
       "  'feature_idx': (2, 3),\n",
       "  'feature_names': ('petal length', 'petal width')},\n",
       " 10: {'avg_score': 0.94000000000000006,\n",
       "  'cv_scores': array([ 0.96666667,  0.96666667,  0.86666667,  0.93333333,  0.96666667]),\n",
       "  'feature_idx': (0, 1, 2),\n",
       "  'feature_names': ('sepal length', 'sepal width', 'petal length')},\n",
       " 11: {'avg_score': 0.94666666666666666,\n",
       "  'cv_scores': array([ 0.93333333,  0.96666667,  0.9       ,  0.93333333,  1.        ]),\n",
       "  'feature_idx': (0, 1, 3),\n",
       "  'feature_names': ('sepal length', 'sepal width', 'petal width')},\n",
       " 12: {'avg_score': 0.97333333333333338,\n",
       "  'cv_scores': array([ 0.96666667,  0.96666667,  0.96666667,  0.96666667,  1.        ]),\n",
       "  'feature_idx': (0, 2, 3),\n",
       "  'feature_names': ('sepal length', 'petal length', 'petal width')},\n",
       " 13: {'avg_score': 0.95999999999999996,\n",
       "  'cv_scores': array([ 0.96666667,  0.96666667,  0.93333333,  0.93333333,  1.        ]),\n",
       "  'feature_idx': (1, 2, 3),\n",
       "  'feature_names': ('sepal width', 'petal length', 'petal width')},\n",
       " 14: {'avg_score': 0.96666666666666679,\n",
       "  'cv_scores': array([ 0.96666667,  0.96666667,  0.93333333,  0.96666667,  1.        ]),\n",
       "  'feature_idx': (0, 1, 2, 3),\n",
       "  'feature_names': ('sepal length',\n",
       "   'sepal width',\n",
       "   'petal length',\n",
       "   'petal width')}}"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "efs1.subsets_"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example 2 - Visualizing the feature selection results"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " For our convenience, we can visualize the output from the feature selection in a pandas DataFrame format using the `get_metric_dict` method of the `ExhaustiveFeatureSelector` object. The columns `std_dev` and `std_err` represent the standard deviation and standard errors of the cross-validation scores, respectively."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Below, we see the DataFrame of the Sequential Forward Selector from Example 2:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Features: 15/15"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>avg_score</th>\n",
       "      <th>ci_bound</th>\n",
       "      <th>cv_scores</th>\n",
       "      <th>feature_idx</th>\n",
       "      <th>feature_names</th>\n",
       "      <th>std_dev</th>\n",
       "      <th>std_err</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>12</th>\n",
       "      <td>0.973333</td>\n",
       "      <td>0.0171372</td>\n",
       "      <td>[0.966666666667, 0.966666666667, 0.96666666666...</td>\n",
       "      <td>(0, 2, 3)</td>\n",
       "      <td>(sepal length, petal length, petal width)</td>\n",
       "      <td>0.0133333</td>\n",
       "      <td>0.00666667</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>14</th>\n",
       "      <td>0.966667</td>\n",
       "      <td>0.0270963</td>\n",
       "      <td>[0.966666666667, 0.966666666667, 0.93333333333...</td>\n",
       "      <td>(0, 1, 2, 3)</td>\n",
       "      <td>(sepal length, sepal width, petal length, peta...</td>\n",
       "      <td>0.0210819</td>\n",
       "      <td>0.0105409</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>13</th>\n",
       "      <td>0.96</td>\n",
       "      <td>0.0320608</td>\n",
       "      <td>[0.966666666667, 0.966666666667, 0.93333333333...</td>\n",
       "      <td>(1, 2, 3)</td>\n",
       "      <td>(sepal width, petal length, petal width)</td>\n",
       "      <td>0.0249444</td>\n",
       "      <td>0.0124722</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>0.953333</td>\n",
       "      <td>0.0514116</td>\n",
       "      <td>[0.933333333333, 1.0, 0.9, 0.933333333333, 1.0]</td>\n",
       "      <td>(2,)</td>\n",
       "      <td>(petal length,)</td>\n",
       "      <td>0.04</td>\n",
       "      <td>0.02</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>0.953333</td>\n",
       "      <td>0.0436915</td>\n",
       "      <td>[0.966666666667, 0.966666666667, 0.9, 0.933333...</td>\n",
       "      <td>(0, 3)</td>\n",
       "      <td>(sepal length, petal width)</td>\n",
       "      <td>0.0339935</td>\n",
       "      <td>0.0169967</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>0.953333</td>\n",
       "      <td>0.0436915</td>\n",
       "      <td>[0.966666666667, 0.966666666667, 0.9, 0.933333...</td>\n",
       "      <td>(2, 3)</td>\n",
       "      <td>(petal length, petal width)</td>\n",
       "      <td>0.0339935</td>\n",
       "      <td>0.0169967</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>0.946667</td>\n",
       "      <td>0.0581151</td>\n",
       "      <td>[0.966666666667, 0.966666666667, 0.93333333333...</td>\n",
       "      <td>(3,)</td>\n",
       "      <td>(petal width,)</td>\n",
       "      <td>0.0452155</td>\n",
       "      <td>0.0226078</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>0.946667</td>\n",
       "      <td>0.0581151</td>\n",
       "      <td>[0.966666666667, 1.0, 0.866666666667, 0.933333...</td>\n",
       "      <td>(0, 2)</td>\n",
       "      <td>(sepal length, petal length)</td>\n",
       "      <td>0.0452155</td>\n",
       "      <td>0.0226078</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>0.946667</td>\n",
       "      <td>0.0436915</td>\n",
       "      <td>[0.966666666667, 1.0, 0.9, 0.933333333333, 0.9...</td>\n",
       "      <td>(1, 2)</td>\n",
       "      <td>(sepal width, petal length)</td>\n",
       "      <td>0.0339935</td>\n",
       "      <td>0.0169967</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11</th>\n",
       "      <td>0.946667</td>\n",
       "      <td>0.0436915</td>\n",
       "      <td>[0.933333333333, 0.966666666667, 0.9, 0.933333...</td>\n",
       "      <td>(0, 1, 3)</td>\n",
       "      <td>(sepal length, sepal width, petal width)</td>\n",
       "      <td>0.0339935</td>\n",
       "      <td>0.0169967</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>0.94</td>\n",
       "      <td>0.0499631</td>\n",
       "      <td>[0.966666666667, 0.966666666667, 0.86666666666...</td>\n",
       "      <td>(1, 3)</td>\n",
       "      <td>(sepal width, petal width)</td>\n",
       "      <td>0.038873</td>\n",
       "      <td>0.0194365</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>0.94</td>\n",
       "      <td>0.0499631</td>\n",
       "      <td>[0.966666666667, 0.966666666667, 0.86666666666...</td>\n",
       "      <td>(0, 1, 2)</td>\n",
       "      <td>(sepal length, sepal width, petal length)</td>\n",
       "      <td>0.038873</td>\n",
       "      <td>0.0194365</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>0.726667</td>\n",
       "      <td>0.11623</td>\n",
       "      <td>[0.666666666667, 0.8, 0.633333333333, 0.866666...</td>\n",
       "      <td>(0, 1)</td>\n",
       "      <td>(sepal length, sepal width)</td>\n",
       "      <td>0.0904311</td>\n",
       "      <td>0.0452155</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0.66</td>\n",
       "      <td>0.106334</td>\n",
       "      <td>[0.533333333333, 0.633333333333, 0.73333333333...</td>\n",
       "      <td>(0,)</td>\n",
       "      <td>(sepal length,)</td>\n",
       "      <td>0.0827312</td>\n",
       "      <td>0.0413656</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0.566667</td>\n",
       "      <td>0.0605892</td>\n",
       "      <td>[0.533333333333, 0.633333333333, 0.6, 0.5, 0.5...</td>\n",
       "      <td>(1,)</td>\n",
       "      <td>(sepal width,)</td>\n",
       "      <td>0.0471405</td>\n",
       "      <td>0.0235702</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   avg_score   ci_bound                                          cv_scores  \\\n",
       "12  0.973333  0.0171372  [0.966666666667, 0.966666666667, 0.96666666666...   \n",
       "14  0.966667  0.0270963  [0.966666666667, 0.966666666667, 0.93333333333...   \n",
       "13      0.96  0.0320608  [0.966666666667, 0.966666666667, 0.93333333333...   \n",
       "2   0.953333  0.0514116    [0.933333333333, 1.0, 0.9, 0.933333333333, 1.0]   \n",
       "6   0.953333  0.0436915  [0.966666666667, 0.966666666667, 0.9, 0.933333...   \n",
       "9   0.953333  0.0436915  [0.966666666667, 0.966666666667, 0.9, 0.933333...   \n",
       "3   0.946667  0.0581151  [0.966666666667, 0.966666666667, 0.93333333333...   \n",
       "5   0.946667  0.0581151  [0.966666666667, 1.0, 0.866666666667, 0.933333...   \n",
       "7   0.946667  0.0436915  [0.966666666667, 1.0, 0.9, 0.933333333333, 0.9...   \n",
       "11  0.946667  0.0436915  [0.933333333333, 0.966666666667, 0.9, 0.933333...   \n",
       "8       0.94  0.0499631  [0.966666666667, 0.966666666667, 0.86666666666...   \n",
       "10      0.94  0.0499631  [0.966666666667, 0.966666666667, 0.86666666666...   \n",
       "4   0.726667    0.11623  [0.666666666667, 0.8, 0.633333333333, 0.866666...   \n",
       "0       0.66   0.106334  [0.533333333333, 0.633333333333, 0.73333333333...   \n",
       "1   0.566667  0.0605892  [0.533333333333, 0.633333333333, 0.6, 0.5, 0.5...   \n",
       "\n",
       "     feature_idx                                      feature_names  \\\n",
       "12     (0, 2, 3)          (sepal length, petal length, petal width)   \n",
       "14  (0, 1, 2, 3)  (sepal length, sepal width, petal length, peta...   \n",
       "13     (1, 2, 3)           (sepal width, petal length, petal width)   \n",
       "2           (2,)                                    (petal length,)   \n",
       "6         (0, 3)                        (sepal length, petal width)   \n",
       "9         (2, 3)                        (petal length, petal width)   \n",
       "3           (3,)                                     (petal width,)   \n",
       "5         (0, 2)                       (sepal length, petal length)   \n",
       "7         (1, 2)                        (sepal width, petal length)   \n",
       "11     (0, 1, 3)           (sepal length, sepal width, petal width)   \n",
       "8         (1, 3)                         (sepal width, petal width)   \n",
       "10     (0, 1, 2)          (sepal length, sepal width, petal length)   \n",
       "4         (0, 1)                        (sepal length, sepal width)   \n",
       "0           (0,)                                    (sepal length,)   \n",
       "1           (1,)                                     (sepal width,)   \n",
       "\n",
       "      std_dev     std_err  \n",
       "12  0.0133333  0.00666667  \n",
       "14  0.0210819   0.0105409  \n",
       "13  0.0249444   0.0124722  \n",
       "2        0.04        0.02  \n",
       "6   0.0339935   0.0169967  \n",
       "9   0.0339935   0.0169967  \n",
       "3   0.0452155   0.0226078  \n",
       "5   0.0452155   0.0226078  \n",
       "7   0.0339935   0.0169967  \n",
       "11  0.0339935   0.0169967  \n",
       "8    0.038873   0.0194365  \n",
       "10   0.038873   0.0194365  \n",
       "4   0.0904311   0.0452155  \n",
       "0   0.0827312   0.0413656  \n",
       "1   0.0471405   0.0235702  "
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import pandas as pd\n",
    "\n",
    "iris = load_iris()\n",
    "X = iris.data\n",
    "y = iris.target\n",
    "\n",
    "knn = KNeighborsClassifier(n_neighbors=3)\n",
    "\n",
    "efs1 = EFS(knn, \n",
    "           min_features=1,\n",
    "           max_features=4,\n",
    "           scoring='accuracy',\n",
    "           print_progress=True,\n",
    "           cv=5)\n",
    "\n",
    "feature_names = ('sepal length', 'sepal width',\n",
    "                 'petal length', 'petal width')\n",
    "efs1 = efs1.fit(X, y, custom_feature_names=feature_names)\n",
    "\n",
    "df = pd.DataFrame.from_dict(efs1.get_metric_dict()).T\n",
    "df.sort_values('avg_score', inplace=True, ascending=False)\n",
    "df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x1168c96d8>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "metric_dict = efs1.get_metric_dict()\n",
    "\n",
    "fig = plt.figure()\n",
    "k_feat = sorted(metric_dict.keys())\n",
    "avg = [metric_dict[k]['avg_score'] for k in k_feat]\n",
    "\n",
    "upper, lower = [], []\n",
    "for k in k_feat:\n",
    "    upper.append(metric_dict[k]['avg_score'] +\n",
    "                 metric_dict[k]['std_dev'])\n",
    "    lower.append(metric_dict[k]['avg_score'] -\n",
    "                 metric_dict[k]['std_dev'])\n",
    "    \n",
    "plt.fill_between(k_feat,\n",
    "                 upper,\n",
    "                 lower,\n",
    "                 alpha=0.2,\n",
    "                 color='blue',\n",
    "                 lw=1)\n",
    "\n",
    "plt.plot(k_feat, avg, color='blue', marker='o')\n",
    "plt.ylabel('Accuracy +/- Standard Deviation')\n",
    "plt.xlabel('Number of Features')\n",
    "feature_min = len(metric_dict[k_feat[0]]['feature_idx'])\n",
    "feature_max = len(metric_dict[k_feat[-1]]['feature_idx'])\n",
    "plt.xticks(k_feat, \n",
    "           [str(metric_dict[k]['feature_names']) for k in k_feat], \n",
    "           rotation=90)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example 3 - Exhaustive Feature Selection for Regression"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Similar to the classification examples above, the `SequentialFeatureSelector` also supports scikit-learn's estimators\n",
    "for regression."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Features: 377/377"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Best subset: (0, 1, 4, 6, 7, 8, 9, 10, 11, 12)\n"
     ]
    }
   ],
   "source": [
    "from sklearn.linear_model import LinearRegression\n",
    "from sklearn.datasets import load_boston\n",
    "\n",
    "boston = load_boston()\n",
    "X, y = boston.data, boston.target\n",
    "\n",
    "lr = LinearRegression()\n",
    "\n",
    "efs = EFS(lr, \n",
    "          min_features=10,\n",
    "          max_features=12,\n",
    "          scoring='neg_mean_squared_error',\n",
    "          cv=10)\n",
    "\n",
    "efs.fit(X, y)\n",
    "\n",
    "print('Best MSE score: %.2f' % efs.best_score_ * (-1))\n",
    "print('Best subset:', efs.best_idx_)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "## Example 4 - Using the Selected Feature Subset For Making New Predictions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Initialize the dataset\n",
    "\n",
    "from sklearn.neighbors import KNeighborsClassifier\n",
    "from sklearn.datasets import load_iris\n",
    "from sklearn.model_selection import train_test_split\n",
    "\n",
    "iris = load_iris()\n",
    "X, y = iris.data, iris.target\n",
    "X_train, X_test, y_train, y_test = train_test_split(\n",
    "         X, y, test_size=0.33, random_state=1)\n",
    "\n",
    "knn = KNeighborsClassifier(n_neighbors=3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Features: 15/15"
     ]
    }
   ],
   "source": [
    "# Select the \"best\" three features via\n",
    "# 5-fold cross-validation on the training set.\n",
    "\n",
    "from mlxtend.feature_selection import ExhaustiveFeatureSelector as EFS\n",
    "\n",
    "efs1 = EFS(knn, \n",
    "           min_features=1,\n",
    "           max_features=4,\n",
    "           scoring='accuracy',\n",
    "           cv=5)\n",
    "efs1 = efs1.fit(X_train, y_train)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Selected features: (2, 3)\n"
     ]
    }
   ],
   "source": [
    "print('Selected features:', efs1.best_idx_)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Test set accuracy: 96.00 %\n"
     ]
    }
   ],
   "source": [
    "# Generate the new subsets based on the selected features\n",
    "# Note that the transform call is equivalent to\n",
    "# X_train[:, efs1.k_feature_idx_]\n",
    "\n",
    "X_train_efs = efs1.transform(X_train)\n",
    "X_test_efs = efs1.transform(X_test)\n",
    "\n",
    "# Fit the estimator using the new feature subset\n",
    "# and make a prediction on the test data\n",
    "knn.fit(X_train_efs, y_train)\n",
    "y_pred = knn.predict(X_test_efs)\n",
    "\n",
    "# Compute the accuracy of the prediction\n",
    "acc = float((y_test == y_pred).sum()) / y_pred.shape[0]\n",
    "print('Test set accuracy: %.2f %%' % (acc*100))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example 5 - Exhaustive Feature Selection and GridSearch"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Initialize the dataset\n",
    "\n",
    "from sklearn.datasets import load_iris\n",
    "from sklearn.model_selection import train_test_split\n",
    "\n",
    "iris = load_iris()\n",
    "X, y = iris.data, iris.target\n",
    "X_train, X_test, y_train, y_test = train_test_split(\n",
    "         X, y, test_size=0.33, random_state=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Use scikit-learn's `GridSearch` to tune the hyperparameters of the `LogisticRegression` estimator inside the `ExhaustiveFeatureSelector` and use it for prediction in the pipeline. **Note that the `clone_estimator` attribute needs to be set to `False`.**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Fitting 2 folds for each of 3 candidates, totalling 6 fits\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[Parallel(n_jobs=1)]: Done   6 out of   6 | elapsed:    2.7s finished\n"
     ]
    }
   ],
   "source": [
    "from sklearn.model_selection import GridSearchCV\n",
    "from sklearn.pipeline import make_pipeline\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "from mlxtend.feature_selection import ExhaustiveFeatureSelector as EFS\n",
    "\n",
    "lr = LogisticRegression(multi_class='multinomial', \n",
    "                        solver='lbfgs', \n",
    "                        random_state=123)\n",
    "\n",
    "efs1 = EFS(estimator=lr, \n",
    "           min_features=2,\n",
    "           max_features=3,\n",
    "           scoring='accuracy',\n",
    "           print_progress=False,\n",
    "           clone_estimator=False,\n",
    "           cv=5,\n",
    "           n_jobs=1)\n",
    "\n",
    "pipe = make_pipeline(efs1, lr)\n",
    "\n",
    "param_grid = {'exhaustivefeatureselector__estimator__C': [0.1, 1.0, 10.0]}\n",
    "    \n",
    "gs = GridSearchCV(estimator=pipe, \n",
    "                  param_grid=param_grid, \n",
    "                  scoring='accuracy', \n",
    "                  n_jobs=1, \n",
    "                  cv=2, \n",
    "                  verbose=1, \n",
    "                  refit=False)\n",
    "\n",
    "# run gridearch\n",
    "gs = gs.fit(X_train, y_train)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "... and the \"best\" parameters determined by GridSearch are ..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Best parameters via GridSearch {'exhaustivefeatureselector__estimator__C': 1.0}\n"
     ]
    }
   ],
   "source": [
    "print(\"Best parameters via GridSearch\", gs.best_params_)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Obtaining the best *k* feature indices after GridSearch"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If we are interested in the best *k* best feature indices via `SequentialFeatureSelection.best_idx_`, we have to initialize a `GridSearchCV` object with `refit=True`. Now, the grid search object will take the complete training dataset and the best parameters, which it found via cross-validation, to train the estimator pipeline."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "gs = GridSearchCV(estimator=pipe, \n",
    "                  param_grid=param_grid, \n",
    "                  scoring='accuracy', \n",
    "                  n_jobs=1, \n",
    "                  cv=2, \n",
    "                  verbose=1, \n",
    "                  refit=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After running the grid search, we can access the individual pipeline objects of the `best_estimator_` via the `steps` attribute."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Fitting 2 folds for each of 3 candidates, totalling 6 fits\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[Parallel(n_jobs=1)]: Done   6 out of   6 | elapsed:    2.9s finished\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[('exhaustivefeatureselector',\n",
       "  ExhaustiveFeatureSelector(clone_estimator=False, cv=5,\n",
       "               estimator=LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,\n",
       "            intercept_scaling=1, max_iter=100, multi_class='multinomial',\n",
       "            n_jobs=1, penalty='l2', random_state=123, solver='lbfgs',\n",
       "            tol=0.0001, verbose=0, warm_start=False),\n",
       "               max_features=3, min_features=2, n_jobs=1,\n",
       "               pre_dispatch='2*n_jobs', print_progress=False,\n",
       "               scoring='accuracy')),\n",
       " ('logisticregression',\n",
       "  LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,\n",
       "            intercept_scaling=1, max_iter=100, multi_class='multinomial',\n",
       "            n_jobs=1, penalty='l2', random_state=123, solver='lbfgs',\n",
       "            tol=0.0001, verbose=0, warm_start=False))]"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "gs = gs.fit(X_train, y_train)\n",
    "gs.best_estimator_.steps"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Via sub-indexing, we can then obtain the best-selected feature subset:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Best features: (2, 3)\n"
     ]
    }
   ],
   "source": [
    "print('Best features:', gs.best_estimator_.steps[0][1].best_idx_)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "During cross-validation, this feature combination had a CV accuracy of:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Best score: 0.97\n"
     ]
    }
   ],
   "source": [
    "print('Best score:', gs.best_score_)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'exhaustivefeatureselector__estimator__C': 1.0}"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "gs.best_params_"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Alternatively**, if we can set the \"best grid search parameters\" in our pipeline manually if we ran `GridSearchCV` with `refit=False`. It should yield the same results:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Best features: (2, 3)\n"
     ]
    }
   ],
   "source": [
    "pipe.set_params(**gs.best_params_).fit(X_train, y_train)\n",
    "print('Best features:', pipe.steps[0][1].best_idx_)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example 6 - Working with pandas DataFrames"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Optionally, we can also use pandas DataFrames and pandas Series as input to the `fit` function. In this case, the column names of the pandas DataFrame will be used as feature names. However, note that if `custom_feature_names` are provided in the fit function, these `custom_feature_names` take precedence over the DataFrame column-based feature names."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "from sklearn.neighbors import KNeighborsClassifier\n",
    "from sklearn.datasets import load_iris\n",
    "\n",
    "iris = load_iris()\n",
    "col_names = ('sepal length', 'sepal width',\n",
    "             'petal length', 'petal width')\n",
    "X_df = pd.DataFrame(iris.data, columns=col_names)\n",
    "y_series = pd.Series(iris.target)\n",
    "knn = KNeighborsClassifier(n_neighbors=4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Features: 15/15"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Best accuracy score: 0.97\n",
      "Best subset (indices): (0, 2, 3)\n",
      "Best subset (corresponding names): ('sepal length', 'petal length', 'petal width')\n"
     ]
    }
   ],
   "source": [
    "from mlxtend.feature_selection import ExhaustiveFeatureSelector as EFS\n",
    "\n",
    "knn = KNeighborsClassifier(n_neighbors=3)\n",
    "\n",
    "efs1 = EFS(knn, \n",
    "           min_features=1,\n",
    "           max_features=4,\n",
    "           scoring='accuracy',\n",
    "           print_progress=True,\n",
    "           cv=5)\n",
    "\n",
    "efs1 = efs1.fit(X_df, y_series)\n",
    "\n",
    "print('Best accuracy score: %.2f' % efs1.best_score_)\n",
    "print('Best subset (indices):', efs1.best_idx_)\n",
    "print('Best subset (corresponding names):', efs1.best_feature_names_)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## API"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "## ExhaustiveFeatureSelector\n",
      "\n",
      "*ExhaustiveFeatureSelector(estimator, min_features=1, max_features=1, print_progress=True, scoring='accuracy', cv=5, n_jobs=1, pre_dispatch='2*n_jobs', clone_estimator=True)*\n",
      "\n",
      "Exhaustive Feature Selection for Classification and Regression.\n",
      "(new in v0.4.3)\n",
      "\n",
      "**Parameters**\n",
      "\n",
      "- `estimator` : scikit-learn classifier or regressor\n",
      "\n",
      "\n",
      "- `min_features` : int (default: 1)\n",
      "\n",
      "    Minumum number of features to select\n",
      "\n",
      "- `max_features` : int (default: 1)\n",
      "\n",
      "    Maximum number of features to select\n",
      "\n",
      "- `print_progress` : bool (default: True)\n",
      "\n",
      "    Prints progress as the number of epochs\n",
      "    to stderr.\n",
      "\n",
      "- `scoring` : str, (default='accuracy')\n",
      "\n",
      "    Scoring metric in {accuracy, f1, precision, recall, roc_auc}\n",
      "    for classifiers,\n",
      "    {'mean_absolute_error', 'mean_squared_error',\n",
      "    'median_absolute_error', 'r2'} for regressors,\n",
      "    or a callable object or function with\n",
      "    signature ``scorer(estimator, X, y)``.\n",
      "\n",
      "- `cv` : int (default: 5)\n",
      "\n",
      "    Scikit-learn cross-validation generator or `int`.\n",
      "    If estimator is a classifier (or y consists of integer class labels),\n",
      "    stratified k-fold is performed, and regular k-fold cross-validation\n",
      "    otherwise.\n",
      "    No cross-validation if cv is None, False, or 0.\n",
      "\n",
      "- `n_jobs` : int (default: 1)\n",
      "\n",
      "    The number of CPUs to use for evaluating different feature subsets\n",
      "    in parallel. -1 means 'all CPUs'.\n",
      "\n",
      "- `pre_dispatch` : int, or string (default: '2*n_jobs')\n",
      "\n",
      "    Controls the number of jobs that get dispatched\n",
      "    during parallel execution if `n_jobs > 1` or `n_jobs=-1`.\n",
      "    Reducing this number can be useful to avoid an explosion of\n",
      "    memory consumption when more jobs get dispatched than CPUs can process.\n",
      "    This parameter can be:\n",
      "    None, in which case all the jobs are immediately created and spawned.\n",
      "    Use this for lightweight and fast-running jobs,\n",
      "    to avoid delays due to on-demand spawning of the jobs\n",
      "    An int, giving the exact number of total jobs that are spawned\n",
      "    A string, giving an expression as a function\n",
      "    of n_jobs, as in `2*n_jobs`\n",
      "\n",
      "- `clone_estimator` : bool (default: True)\n",
      "\n",
      "    Clones estimator if True; works with the original estimator instance\n",
      "    if False. Set to False if the estimator doesn't\n",
      "    implement scikit-learn's set_params and get_params methods.\n",
      "    In addition, it is required to set cv=0, and n_jobs=1.\n",
      "\n",
      "**Attributes**\n",
      "\n",
      "- `best_idx_` : array-like, shape = [n_predictions]\n",
      "\n",
      "    Feature Indices of the selected feature subsets.\n",
      "\n",
      "- `best_feature_names_` : array-like, shape = [n_predictions]\n",
      "\n",
      "    Feature names of the selected feature subsets. If pandas\n",
      "    DataFrames are used in the `fit` method, the feature\n",
      "    names correspond to the column names. Otherwise, the\n",
      "    feature names are string representation of the feature\n",
      "    array indices. New in v 0.13.0.\n",
      "\n",
      "- `best_score_` : float\n",
      "\n",
      "    Cross validation average score of the selected subset.\n",
      "\n",
      "- `subsets_` : dict\n",
      "\n",
      "    A dictionary of selected feature subsets during the\n",
      "    exhaustive selection, where the dictionary keys are\n",
      "    the lengths k of these feature subsets. The dictionary\n",
      "    values are dictionaries themselves with the following\n",
      "    keys: 'feature_idx' (tuple of indices of the feature subset)\n",
      "    'feature_names' (tuple of feature names of the feat. subset)\n",
      "    'cv_scores' (list individual cross-validation scores)\n",
      "    'avg_score' (average cross-validation score)\n",
      "    Note that if pandas\n",
      "    DataFrames are used in the `fit` method, the 'feature_names'\n",
      "    correspond to the column names. Otherwise, the\n",
      "    feature names are string representation of the feature\n",
      "    array indices. The 'feature_names' is new in v 0.13.0.\n",
      "\n",
      "**Examples**\n",
      "\n",
      "For usage examples, please see\n",
      "    [http://rasbt.github.io/mlxtend/user_guide/feature_selection/ExhaustiveFeatureSelector/](http://rasbt.github.io/mlxtend/user_guide/feature_selection/ExhaustiveFeatureSelector/)\n",
      "\n",
      "### Methods\n",
      "\n",
      "<hr>\n",
      "\n",
      "*fit(X, y, custom_feature_names=None, **fit_params)*\n",
      "\n",
      "Perform feature selection and learn model from training data.\n",
      "\n",
      "**Parameters**\n",
      "\n",
      "- `X` : {array-like, sparse matrix}, shape = [n_samples, n_features]\n",
      "\n",
      "    Training vectors, where n_samples is the number of samples and\n",
      "    n_features is the number of features.\n",
      "    New in v 0.13.0: pandas DataFrames are now also accepted as\n",
      "    argument for X.\n",
      "\n",
      "- `y` : array-like, shape = [n_samples]\n",
      "\n",
      "    Target values.\n",
      "\n",
      "- `custom_feature_names` : None or tuple (default: tuple)\n",
      "\n",
      "    Custom feature names for `self.k_feature_names` and\n",
      "    `self.subsets_[i]['feature_names']`.\n",
      "    (new in v 0.13.0)\n",
      "\n",
      "- `fit_params` : dict of string -> object, optional\n",
      "\n",
      "    Parameters to pass to to the fit method of classifier.\n",
      "\n",
      "**Returns**\n",
      "\n",
      "- `self` : object\n",
      "\n",
      "\n",
      "<hr>\n",
      "\n",
      "*fit_transform(X, y, **fit_params)*\n",
      "\n",
      "Fit to training data and return the best selected features from X.\n",
      "\n",
      "**Parameters**\n",
      "\n",
      "- `X` : {array-like, sparse matrix}, shape = [n_samples, n_features]\n",
      "\n",
      "    Training vectors, where n_samples is the number of samples and\n",
      "    n_features is the number of features.\n",
      "    New in v 0.13.0: pandas DataFrames are now also accepted as\n",
      "    argument for X.\n",
      "\n",
      "- `y` : array-like, shape = [n_samples]\n",
      "\n",
      "    Target values.\n",
      "\n",
      "- `fit_params` : dict of string -> object, optional\n",
      "\n",
      "    Parameters to pass to to the fit method of classifier.\n",
      "\n",
      "**Returns**\n",
      "\n",
      "Feature subset of X, shape={n_samples, k_features}\n",
      "\n",
      "<hr>\n",
      "\n",
      "*get_metric_dict(confidence_interval=0.95)*\n",
      "\n",
      "Return metric dictionary\n",
      "\n",
      "**Parameters**\n",
      "\n",
      "- `confidence_interval` : float (default: 0.95)\n",
      "\n",
      "    A positive float between 0.0 and 1.0 to compute the confidence\n",
      "    interval bounds of the CV score averages.\n",
      "\n",
      "**Returns**\n",
      "\n",
      "Dictionary with items where each dictionary value is a list\n",
      "    with the number of iterations (number of feature subsets) as\n",
      "    its length. The dictionary keys corresponding to these lists\n",
      "    are as follows:\n",
      "    'feature_idx': tuple of the indices of the feature subset\n",
      "    'cv_scores': list with individual CV scores\n",
      "    'avg_score': of CV average scores\n",
      "    'std_dev': standard deviation of the CV score average\n",
      "    'std_err': standard error of the CV score average\n",
      "    'ci_bound': confidence interval bound of the CV score average\n",
      "\n",
      "<hr>\n",
      "\n",
      "*get_params(deep=True)*\n",
      "\n",
      "Get parameters for this estimator.\n",
      "\n",
      "**Parameters**\n",
      "\n",
      "- `deep` : boolean, optional\n",
      "\n",
      "    If True, will return the parameters for this estimator and\n",
      "    contained subobjects that are estimators.\n",
      "\n",
      "**Returns**\n",
      "\n",
      "- `params` : mapping of string to any\n",
      "\n",
      "    Parameter names mapped to their values.\n",
      "\n",
      "<hr>\n",
      "\n",
      "*set_params(**params)*\n",
      "\n",
      "Set the parameters of this estimator.\n",
      "\n",
      "The method works on simple estimators as well as on nested objects\n",
      "(such as pipelines). The latter have parameters of the form\n",
      "``<component>__<parameter>`` so that it's possible to update each\n",
      "component of a nested object.\n",
      "\n",
      "**Returns**\n",
      "\n",
      "self\n",
      "\n",
      "<hr>\n",
      "\n",
      "*transform(X)*\n",
      "\n",
      "Return the best selected features from X.\n",
      "\n",
      "**Parameters**\n",
      "\n",
      "- `X` : {array-like, sparse matrix}, shape = [n_samples, n_features]\n",
      "\n",
      "    Training vectors, where n_samples is the number of samples and\n",
      "    n_features is the number of features.\n",
      "    New in v 0.13.0: pandas DataFrames are now also accepted as\n",
      "    argument for X.\n",
      "\n",
      "**Returns**\n",
      "\n",
      "Feature subset of X, shape={n_samples, k_features}\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "with open('../../api_modules/mlxtend.feature_selection/ExhaustiveFeatureSelector.md', 'r') as f:\n",
    "    print(f.read())"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  },
  "toc": {
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
